/*
Copyright (C) 2008, 2009 Henrik Naess

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using MatrixPlugin.Constants;
using MatrixPlugin.Utils;
using MatrixPlugin.Integration;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Data.GPS;
using ZoneFiveSoftware.Common.Visuals;

namespace MatrixPlugin
{
    public sealed class SettingsController
    {
        private static SettingsController _instance;
        private DateTime _lastUpdated = DateTime.MinValue;

        private XmlDocument _preferences;

        private SettingsController()
        {
            if (!Load())
                ResetToDefaultSettings(true);
        }

        public static SettingsController Instance()
        {
            // Use 'Lazy initialization'
            if (_instance == null)
                _instance = new SettingsController();

            return _instance;
        }
        public DateTime LastUpdated
        {
            get { return _lastUpdated; }
        }

        /// <summary>
        /// Reset to default settings
        /// </summary>
        public void ResetToDefaultSettings(bool clearAllCustomPositionGroup)
        {
            ResetPreferencesXml();
            Directory.CreateDirectory(Preferences.FilePath);
            if (clearAllCustomPositionGroup)
            {
                FileUtility.DeleteFiles(Preferences.FilePath, "*.xml");
            }
            DefaultValues.CreateExamplePositionGroupXmls();

            Save();
        }

        public bool Load()
        {
            trailsPlugin = null;
            _positionGroups = null;

            bool returnValue = false;
            if (File.Exists(Preferences.FullFileName))
            {
                XmlTextReader reader = null;
                _preferences = new XmlDocument();
                try
                {
                    reader = new XmlTextReader(Preferences.FullFileName);
                    _preferences.Load(reader);
                    returnValue = true;
                    _lastUpdated = DateTime.Now;
                }
                catch (Exception exception)
                {
                    MessageBox.Show(
                        string.Format(Properties.Resources.SC_OtherPluginError,
                                      Properties.Resources.ApplicationName, exception));
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Close();
                    }
                }
            }
            return returnValue;
        }

        private void ResetPreferencesXml()
        {
            _preferences = new XmlDocument();
            _preferences.LoadXml(DefaultValues.DefaultPreferencesXmlContent);
        }

        public void Reset()
        {
            _positionGroups = null;
            TrailsPlugin.Refresh();
        }
        /// <summary>
        /// Save user preferences to file
        /// </summary>
        private void Save()
        {
            FileUtility.WriteXmlFile(Preferences.FullFileName, _preferences);
            _lastUpdated = DateTime.Now;
        }

        public PositionGroup DefaultPositionGroup
        {
            get
            {
                XmlNode node = _preferences.SelectSingleNode("MatrixPlugin/Positions");
                PositionGroup defaultPositionGroup = new PositionGroup(node);
                return defaultPositionGroup;
            }
        }

        private Dictionary<String, PositionGroup> _positionGroups = null;
        public Dictionary<String, PositionGroup> PositionGroups
        {
            get
            {
                if (null == _positionGroups)
                {
                    _positionGroups = new Dictionary<String, PositionGroup>();
                    Dictionary<string, PositionGroup> positionGroups = new Dictionary<String, PositionGroup>();

                    AddPositionGroupsFromPreferenceXml(DefaultPositionGroup, ref positionGroups);
                    //No sorting here
                    foreach (KeyValuePair<String, PositionGroup> k in positionGroups)
                    {
                        if (!_positionGroups.ContainsKey(k.Key))
                        {
                            _positionGroups.Add(k.Key, k.Value);
                        }
                    }
                    //Clear
                    positionGroups = new Dictionary<String, PositionGroup>();

                    AddPositionGroupsFromLaps(ref positionGroups);
                    //No sorting here
                    foreach (KeyValuePair<String, PositionGroup> k in positionGroups)
                    {
                        if (!_positionGroups.ContainsKey(k.Key))
                        {
                            _positionGroups.Add(k.Key, k.Value);
                        }
                    }
                    //Clear
                    positionGroups = new Dictionary<String, PositionGroup>();

                    TrailsPlugin.AddPositionGroupsFromTrails(ref positionGroups);
                    //SortedDictionary would have been easier if used from the start
                    //that would also require that this is the final sorting (or add other attributes somehow)
                    List<string> keys = new List<string>(positionGroups.Keys);
                    keys.Sort();
                    foreach (string key in keys)
                    {
                        string name = key;
                        if (_positionGroups.ContainsKey(name))
                        {
                            //Try renaming the trail (once only)
                            string name2 = name + "-Trails";
                            if (_positionGroups.ContainsKey(name2))
                            {
                                System.Windows.Forms.MessageBox.Show(string.Format(Properties.Resources.TrailsPositionGroupExistsAlready, name));
                            }
                            else
                            {
                                name = name2;
                            }
                        }
                        if (!_positionGroups.ContainsKey(name))
                        {
                            _positionGroups.Add(name, positionGroups[key]);
                        }
                    }
                }
                return _positionGroups;
            }
        }

        public void AddPositionGroupsFromLaps(ref Dictionary<string, PositionGroup> positions)
        {
            PositionGroup positionGroup = new PositionGroup(CommonResources.Text.LabelSplits, true);
            positions.Add(positionGroup.Name, positionGroup);
        }
        //private void AddPositionGroupsFromOtherXml(PositionGroup defaultPositionGroup,
        //                                           ref Dictionary<string, PositionGroup> positions)
        //{
        //    string log = null;

        //    string[] files = Directory.GetFiles(Preferences.FilePath, "*.xml");
        //    foreach (string fileName in files)
        //    {
        //        if (String.Compare(fileName, Preferences.FullFileName, StringComparison.OrdinalIgnoreCase) != 0)
        //        {
        //            PositionGroup positionGroup = null;
        //            try
        //            {
        //                positionGroup = GetPositionGroupFromFile(defaultPositionGroup, fileName);
        //                if (positionGroup.Name != null)
        //                {
        //                    positions.Add(positionGroup.Name, positionGroup);
        //                }
        //            }
        //            catch (Exception ex)
        //            {
        //                log += "Failed to load '" + fileName + "': " + ex.Message + Environment.NewLine;
        //            }
        //        }
        //    }

        //    if (log != null)
        //    {
        //        MessageBox.Show(log, "Error load Position Groups", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        //    }
        //}

        //private PositionGroup GetPositionGroupFromFile(PositionGroup defaultPositionGroup, string fileName)
        //{
        //    XmlTextReader reader = new XmlTextReader(fileName);
        //    XmlDocument doc = new XmlDocument();
        //    doc.Load(reader);
        //    reader.Close();
        //    PositionGroup positionGroup = new PositionGroup(doc.SelectSingleNode("PositionGroup"), defaultPositionGroup);
        //    return positionGroup;
        //}

        private void AddPositionGroupsFromPreferenceXml(PositionGroup defaultPositionGroup,
                                                        ref Dictionary<string, PositionGroup> positions)
        {
            XmlNodeList positionGroupXml = _preferences.SelectNodes("//MatrixPlugin/Positions/PositionGroup");
            if (positionGroupXml != null)
            {
                foreach (XmlNode node in positionGroupXml)
                {
                    PositionGroup positionGroup = new PositionGroup(node, defaultPositionGroup);
                    if (!positions.ContainsKey(positionGroup.Name))
                    {
                        positions.Add(positionGroup.Name, positionGroup);
                    }
                }
            }
        }
        private Trails trailsPlugin = null;
        public Trails TrailsPlugin
        {
            get
            {
                if (trailsPlugin == null)
                {
                    trailsPlugin = new Trails();
                }
                return trailsPlugin;
            }
        }

        //The following could be used to migrate settings from 0.5 and earlier
        //public float ToleranceForLength
        //{
        //    get
        //    {
        //        XmlNode toleranceForLengthXml = _preferences.SelectSingleNode("MatrixPlugin/ToleranceForLength");
        //        return (toleranceForLengthXml) != null
        //                   ? float.Parse(toleranceForLengthXml.InnerText)
        //                   : (float)Settings.MaxRadius;
        //    }
        //    set
        //    {
        //        if (!_isLoading)
        //        {
        //            XmlNode toleranceForLengthXml = _preferences.SelectSingleNode("MatrixPlugin/ToleranceForLength");
        //            toleranceForLengthXml.InnerText = value.ToString();
        //            Save();
        //        }
        //    }
        //}

        //public string ToolTipFormatString
        //{
        //    get
        //    {
        //        XmlNode toolTipNode = _preferences.SelectSingleNode("MatrixPlugin/Tooltip");
        //        return (toolTipNode != null) ? toolTipNode.InnerText : Preferences.TooltipFormatString;
        //    }
        //    set
        //    {
        //        if (!_isLoading)
        //        {
        //            XmlNode toolTipNode = _preferences.SelectSingleNode("MatrixPlugin/Tooltip");
        //            // For support upgrade from 0.3.0.0 to newer
        //            if (toolTipNode == null)
        //            {
        //                //Create a new node and add it to the document.
        //                XmlNode rootNode = _preferences.SelectSingleNode("MatrixPlugin");
        //                toolTipNode = _preferences.CreateNode(XmlNodeType.Element, "Tooltip", null);
        //                toolTipNode.InnerText = Preferences.TooltipFormatString;
        //                rootNode.AppendChild(toolTipNode);
        //            }
        //            else
        //                toolTipNode.InnerText = value;

        //            Save();
        //        }
        //    }
        //}
    }
}